package com.jwater.core.net;

import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jwater.io.netty.bootstrap.ServerBootstrap;
import jwater.io.netty.channel.ChannelFuture;
import jwater.io.netty.channel.ChannelInitializer;
import jwater.io.netty.channel.EventLoopGroup;
import jwater.io.netty.channel.nio.NioEventLoopGroup;
import jwater.io.netty.channel.socket.SocketChannel;
import jwater.io.netty.channel.socket.nio.NioServerSocketChannel;
import jwater.io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import jwater.io.netty.handler.timeout.IdleStateHandler;
import jwater.io.netty.util.concurrent.Future;
/**
 * @description:
 * @author: jnner
 * @createDate: 2021/2/5
 * @version: 1.0
 */
public class NettyServer {
	private Logger logger = LoggerFactory.getLogger(getClass());

	private EventLoopGroup bossGroup = null;
	private EventLoopGroup workerGroup = null;
	private ChannelFuture channelFuture;
	private ServerBootstrap serverBootstrap;
	protected NodeHandler nodeHandler;
	protected FileHandler fileHandler;

	public void init() throws InterruptedException {
		// 创建默认数量的线程池，线程个数为CPU个数*2
		bossGroup = new NioEventLoopGroup();
		workerGroup = new NioEventLoopGroup();
		serverBootstrap = new ServerBootstrap();
		serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
				.childHandler(new ChannelInitializer<SocketChannel>() {
					@Override
					public void initChannel(SocketChannel ch) throws Exception {
						// 解决TCP粘包问题
						ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(10 * 1024 * 1024, 10, 4));
						ch.pipeline().addLast(new NettyEncoder());
						ch.pipeline().addLast(new NettyDecoder());
						// 心跳检查
						int hearttime = SimpleNode.hearttime;
						ch.pipeline().addLast(
								new IdleStateHandler(hearttime * 3, hearttime * 2, hearttime * 2, TimeUnit.SECONDS));
						NettyServerHandler handler = new NettyServerHandler(NettyServer.this);
						ch.pipeline().addLast(handler);
					}
				});
	}

	public void bind(int port, boolean sync) throws InterruptedException {
		channelFuture = serverBootstrap.bind(port);
		logger.info("NettyServer start,port={}", port);
		if (sync) {
			channelFuture.sync();
		}
	}

	public void close() throws InterruptedException {
		if (channelFuture != null) {
			channelFuture.channel().closeFuture();
		}
		if (workerGroup != null) {
			Future<?> future = this.workerGroup.shutdownGracefully().await();
			if (!future.isSuccess()) {
				logger.error("workerGroup can not success stop:{}", future.cause());
			}
		}
		if (bossGroup != null) {
			Future<?> future = this.bossGroup.shutdownGracefully().await();
			if (!future.isSuccess()) {
				logger.error("bossGroup can not success stop:{}", future.cause());
			}
		}
	}

	public void setHandler(NodeHandler nodeHandler, FileHandler fileHandler) {
		this.nodeHandler = nodeHandler;
		this.fileHandler = fileHandler;
	}
}
